// ImageConverter.cpp : Defines the entry point for the console application.
//
#define _CRT_SECURE_NO_WARNINGS
//#define _IN_WINDOWS__

#ifdef  _IN_WINDOWS__
#include <Windows.h>
#endif

#include <GL/gl.h>
#define BYTES_PER_PIXEL		4
#include <stdio.h>

#ifdef  _IN_WINDOWS__
#include <tchar.h>
#endif

#include <string>

#ifdef  _IN_WINDOWS__
#pragma comment(lib, "openGL32.lib")
#pragma comment(lib, "../../../../../SDL-1.2.13/lib/SDL.lib")
#endif

#ifdef  _IN_WINDOWS__
#include "SDL.h"
#else
#include <SDL/SDL.h>
#endif

#define FORMAT_VERIFICATION1		0x12ab65bf
#define FORMAT_VERIFICATION2		0x62a8b09e
#define FORMAT_VERIFICATION3		0x9127dc67
#define FORMAT_VERIFICATION4		0xaa443b10

typedef struct SParams
{
	std::string FileNameSource;
	std::string FileNameDest;
}SParams;

typedef unsigned char u8;
typedef char s8;
typedef unsigned int u32;
typedef int s32;
typedef unsigned short u16;
typedef short s16;

typedef struct DestHeader
{
	u32 FormatVerification1;
	u32 FormatVerification2;
	u16 Width;
	u16 Height;
	u32 FormatVerification3;
	u32 FormatVerification4;
} DestHeader;

u32 CreateOpenGLTextureFromPixels(u32 *pixels,u32 w,u32 h);

void ReadPixel8bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels);
void ReadPixel16bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels);
void ReadPixel24bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels);
void ReadPixel32bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels);

#ifdef  _IN_WINDOWS__
int _tmain(int argc, _TCHAR* argv[])
#else
int main(int argc, char** argv)
#endif
{
	SParams params;

//	params.FileNameSource = "Font.bmp";
//	params.FileNameDest = "Font.gff";
	params.FileNameSource = "ficha.bmp";
	params.FileNameDest = "ficha.gff";

	if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
	{
		printf( "Unable to init SDL: %s\n", SDL_GetError() );
		return 1;
	}

	atexit(SDL_Quit);

	SDL_Surface *Image = SDL_LoadBMP(params.FileNameSource.c_str());
	u8 *DataToWrite;
	DestHeader dh;

	if (Image)
	{
		printf("Reading image %s...\n",params.FileNameSource.c_str());
		printf("Width: %d\n",Image->w);
		printf("Height: %d\n",Image->h);
		printf("Bits per pixel:%d\n",Image->format->BitsPerPixel);

		DataToWrite = (u8*)malloc(sizeof(u8)*4*Image->w*Image->h);
		u8 *Pixels = (u8*)Image->pixels;
		u32 DirDest=0;
		u8 r;
		u8 g;
		u8 b;
		u8 a;
		for (int y=0;y<Image->h;y++)
		{
			for (int x=0;x<Image->w;x++)
			{

				if (Image->format->BitsPerPixel==8)
					ReadPixel8bits(Image,&r,&g,&b,&a,x,y,Pixels);
				else if (Image->format->BitsPerPixel==16)
					ReadPixel16bits(Image,&r,&g,&b,&a,x,y,Pixels);
				else if (Image->format->BitsPerPixel==24)
					ReadPixel24bits(Image,&r,&g,&b,&a,x,y,Pixels);
				else if (Image->format->BitsPerPixel==32)
					ReadPixel32bits(Image,&r,&g,&b,&a,x,y,Pixels);

				DataToWrite[DirDest] = r;
				DirDest++;
				DataToWrite[DirDest] = g;
				DirDest++;
				DataToWrite[DirDest] = b;
				DirDest++;
				DataToWrite[DirDest] = a;
				DirDest++;

/*
				DataToWrite[DirDest] = p[2];
				DirDest++;
				DataToWrite[DirDest] = p[1];
				DirDest++;
				DataToWrite[DirDest] = p[0];
				DirDest++;
				DataToWrite[DirDest] = p[3];
				DirDest++;
*/
			}
		}

		printf("File read. Now we have to create the header of the destination file\n",params.FileNameDest.c_str());

		u32 HeaderLen = sizeof(DestHeader);
		dh.Width = Image->w;
		dh.Height = Image->h;
		dh.FormatVerification1 = FORMAT_VERIFICATION1;
		dh.FormatVerification2 = FORMAT_VERIFICATION2;
		dh.FormatVerification3 = FORMAT_VERIFICATION3;
		dh.FormatVerification4 = FORMAT_VERIFICATION4;

		printf("Creating file for writing\n");
		FILE *fdest = fopen(params.FileNameDest.c_str(),"wb");

		if (fdest)
		{
			printf("File %s created for writing\n",params.FileNameDest.c_str());
			u32 BytesWrote;
			BytesWrote = fwrite(&HeaderLen,1,sizeof(u32),fdest);

			if (BytesWrote!= sizeof(u32))
			{
				printf("Cannot write the header to the file\n");
				exit(-4);
			}

			BytesWrote = fwrite(&dh,1,sizeof(DestHeader),fdest);
			if (BytesWrote != sizeof(DestHeader))
			{
				printf("Cannot write the header to the file\n");
				exit(-4);
			}

			u32 BytesToWrite = dh.Width*dh.Height*4;
			BytesWrote = fwrite(DataToWrite,1,BytesToWrite,fdest);

			if (BytesWrote != BytesToWrite)
			{
				printf("Cannot write the complete file\n");
			}

			fclose(fdest);

			printf("%s created correctly\n",params.FileNameDest.c_str());
		}
		else
		{
			printf("Cannot open file %s for writing\n",params.FileNameDest.c_str());
			exit(-3);
		}
	}
	else
	{
		printf("Source file: %s not found or is not valid\n",params.FileNameSource.c_str());
		exit(-1);
	}

	printf ("Initializing visualization...");

	u32 flags=0;

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);

	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);


	flags |= SDL_OPENGL|SDL_HWSURFACE;

	SDL_Surface *screen = SDL_SetVideoMode(1024,768,0,flags);
//	u32 Texture1 = CreateOpenGLTextureFromPixels((u32*)Image->pixels,Image->w,Image->h);
	u32 Texture2 = CreateOpenGLTextureFromPixels((u32*)DataToWrite,dh.Width,dh.Height);

	float max = dh.Width>dh.Height?dh.Width:dh.Height;
	float xinc = dh.Width / (max / 2);
	float yinc = 2.0f - (dh.Height / (max / 2));

	// program main loop
	bool done = false;
	while (!done)
	{
		// message processing loop
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			// check for messages
			switch (event.type)
			{
				// exit if the window is closed
			case SDL_QUIT:
				done = true;
				break;

				// check for keypresses
			case SDL_KEYDOWN:
				{
					// exit if ESCAPE is pressed
					if (event.key.keysym.sym == SDLK_ESCAPE)
						done = true;
					break;
				}
			} // end switch
		} // end of message processing

		// DRAWING STARTS HERE

		// clear screen
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// draw bitmap
		glPushMatrix();

		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D,Texture2);
		glBegin(GL_QUADS);
		glTexCoord2f(0.0f,1.0f);
		glVertex2f(-1.0f,-1.0f);
		glTexCoord2f(1.0f,1.0f);
		glVertex2f(1.0f,-1.0f);
		glTexCoord2f(1.0f,0.0f);
		glVertex2f(1.0f,1.0f);
		glTexCoord2f(0.0f,0.0f);
		glVertex2f(-1.0f,1.0f);

		glEnd();

		glPopMatrix();

		SDL_GL_SwapBuffers();
	}

	return 0;
}

u32 CreateOpenGLTextureFromPixels(u32 *pixels,u32 w,u32 h)
{
	u32 texture;

	glGenTextures(1,&texture);
	glBindTexture(GL_TEXTURE_2D,texture);

	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

	u32 *RealPixels = pixels;
	RealPixels = (u32*)malloc((w)*(h)*sizeof(u32));
	u32 Count = 0;
	u32 Dir;
	u32 Temp;

	for (u32 yref=0;yref<h;yref++)
	{
		for (u32 xref=0;xref<w;xref++)
		{
			Dir = (yref*w) + xref;
			Temp = pixels[Dir];
			RealPixels[Count] = Temp;
			Count++;
		}
	}

	glTexImage2D(GL_TEXTURE_2D,0,4,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,pixels);

//	if (pixels != RealPixels)
//		free(RealPixels);

	return texture;
}

void ReadPixel8bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels)
{
//	u32 Dir = (y*Image->w)+(x);
	u32 Dir = (y*(Image->pitch))+x;
	u8 Color = Pixels[Dir];
	*r = Image->format->palette->colors[Color].r;
	*g = Image->format->palette->colors[Color].g;
	*b = Image->format->palette->colors[Color].b;
	*a = 0;

	if (x==1 && y==1)
		int h=0;

	if (*r==0 && *g==255 && *b==0)
		int j=0;

}

void ReadPixel16bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels)
{
	u32 Dir = (y*Image->w*Image->format->BytesPerPixel)+(x*Image->format->BytesPerPixel);
	*r = Pixels[Dir];
	Dir++;

	*g = Pixels[Dir];

	*b = 0;
	*a = 0;
}

void ReadPixel24bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels)
{
	u32 Dir = (y*Image->w*Image->format->BytesPerPixel)+(x*Image->format->BytesPerPixel);

	if (Image->format->Rshift==0)
		*r = Pixels[Dir];
	else if (Image->format->Gshift==0)
		*g = Pixels[Dir];
	else if (Image->format->Bshift==0)
		*b = Pixels[Dir];

	Dir++;

	if (Image->format->Rshift==8)
		*r = Pixels[Dir];
	else if (Image->format->Gshift==8)
		*g = Pixels[Dir];
	else if (Image->format->Bshift==8)
		*b = Pixels[Dir];

	Dir++;

	if (Image->format->Rshift==16)
		*r = Pixels[Dir];
	else if (Image->format->Gshift==16)
		*g = Pixels[Dir];
	else if (Image->format->Bshift==16)
		*b = Pixels[Dir];

	*a = 0;
}

void ReadPixel32bits(SDL_Surface *Image,u8 *r,u8 *g,u8 *b,u8 *a,int x,int y,u8 *Pixels)
{
	u32 Dir = (y*Image->w*Image->format->BytesPerPixel)+(x*Image->format->BytesPerPixel);
	*r = Pixels[Dir];
	Dir++;

	*g = Pixels[Dir];
	Dir++;

	*b = Pixels[Dir];
	Dir++;

	*a = Pixels[Dir];
}
